#!/bin/bash

#
# libseccomp code syntax checking tool
#
# Copyright (c) 2013,2015 Red Hat <pmoore@redhat.com>
# Author: Paul Moore <paul@paul-moore.com>
#

#
# This library is free software; you can redistribute it and/or modify it
# under the terms of version 2.1 of the GNU Lesser General Public License as
# published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
# for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this library; if not, see <http://www.gnu.org/licenses>.
#

CHK_C_LIST="include/seccomp.h.in \
	    include/seccomp-syscalls.h \
	    src/*.c src/*.h \
	    tests/*.c tests/*.h \
	    tools/*.c tools/*.h"
CHK_C_EXCLUDE="src/syscalls.perf.c"

CHK_SPELL_EXCLUDE_WORDS=""

####
# functions

#
# Dependency verification
#
# Arguments:
#     1    Dependency to check for
#
function verify_deps() {
	[[ -z "$1" ]] && return
	if ! which "$1" >& /dev/null; then
		echo "error: install \"$1\" and include it in your \$PATH"
		exit 1
	fi
}

#
# Print out script usage details
#
function usage() {
cat << EOF
usage: check-syntax [-h]

libseccomp code syntax checking tool
optional arguments:
  -h             show this help message and exit
  -f             fix the file formatting
EOF
}

#
# Spellcheck source code
#
function tool_spell_check() {
	local tfile

	tfile=$(mktemp -t check-syntax-XXXXXX)
	cat - > $tfile
	codespell -q 16 -d -w -L "$CHK_SPELL_EXCLUDE_WORDS" $tfile
	cat $tfile
	rm -f $tfile
}

#
# Generate a properly formatted C source/header file
#
function tool_c_style() {
	cat - | astyle --options=none --lineend=linux --mode=c \
		--style=linux \
		--indent=force-tab=8 \
		--indent-preprocessor \
		--indent-col1-comments \
		--min-conditional-indent=0 \
		--max-instatement-indent=80 \
		--pad-oper \
		--align-pointer=name \
		--align-reference=name \
		--max-code-length=80 \
		--break-after-logical
}

#
# Generate a properly formatted and spellchecked C source/header file
#
# Arguments:
#     1    Source file
#
function tool_c_ideal() {
	cat "$1" | tool_spell_check | tool_c_style
}

#
# Check the formatting on a C source/header file
#
# Arguments:
#     1    File to check
#
function tool_c_style_check() {
	[[ -z "$1" || ! -r "$1" ]] && return

	tool_c_ideal "$1" | diff -pu --label="$1.orig" "$1" --label="$1" -
}

#
# Fix the formatting on a C source/header file
#
# Arguments:
#     1    File to fix
#
function tool_c_style_fix() {
	[[ -z "$1" || ! -r "$1" ]] && return

	tmp="$(mktemp --tmpdir=$(dirname "$1"))"
	tool_c_ideal "$1" > "$tmp"
	mv "$tmp" "$1"
}

#
# Perform all known syntax checks for the configured C sources/headers
#
function check_c() {
	for i in $CHK_C_LIST; do
		echo "$CHK_C_EXCLUDE" | grep -q "$i" && continue
		echo "Differences for $i"
		tool_c_style_check "$i"
	done
}

#
# Perform all known syntax fixess for the configured C sources/headers
#
function fix_c() {
	for i in $CHK_C_LIST; do
		echo "$CHK_C_EXCLUDE" | grep -q "$i" && continue
		echo "Fixing $i"
		tool_c_style_fix "$i"
	done
}

####
# main

verify_deps astyle
verify_deps codespell

opt_fix=0

while getopts "fh" opt; do
	case $opt in
	f)
		opt_fix=1
		;;
	h|*)
		usage
		exit 1
		;;
	esac
done

# display the results
echo "=============== $(date) ==============="
echo "Code Syntax Check Results (\"check-syntax $*\")"
if [[ $opt_fix -eq 1 ]]; then
	fix_c
else
	check_c
fi
echo "============================================================"

# exit
exit 0
